package uno.rocc.framework.security.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.apache.catalina.connector.Response;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import uno.rocc.common.constant.RedisConstant;
import uno.rocc.common.constant.RespConstant;
import uno.rocc.common.exception.ServiceException;
import uno.rocc.framework.security.domain.RoccUnoUserDetails;
import uno.rocc.framework.security.service.LoginUserService;
import uno.rocc.framework.security.util.JwtUtil;
import uno.rocc.system.domain.dao.SysPermission;
import uno.rocc.system.domain.dao.SysUser;
import uno.rocc.system.domain.dao.SysUserPermission;
import uno.rocc.system.domain.dto.LoginSysUser;
import uno.rocc.system.domain.dto.RegisterSysUser;
import uno.rocc.system.domain.vo.SysUserVo;
import uno.rocc.system.service.SysPermissionService;
import uno.rocc.system.service.SysUserPermissionService;
import uno.rocc.system.service.SysUserService;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class LoginUserServiceImpl implements LoginUserService {
    private final AuthenticationManager authenticationManager;
    private final RedisTemplate<String, Object> redisTemplate;
    private final JwtUtil jwtUtil;
    private final SysUserService sysUserService;
    private final PasswordEncoder bCryptPasswordEncoder;
    private final SysPermissionService sysPermissionService;
    private final SysUserPermissionService sysUserPermissionService;


    @Override
    public Map<String, Object> login(LoginSysUser loginSysUser) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginSysUser.getUsername(), loginSysUser.getPassword());
        Authentication authenticate = authenticationManager.authenticate(token);

        RoccUnoUserDetails principal = (RoccUnoUserDetails) authenticate.getPrincipal();

        //存在则查询用户权限
        LambdaQueryWrapper<SysUserPermission> queryUserPermission = new LambdaQueryWrapper<SysUserPermission>().select(SysUserPermission::getPermissionId).eq(SysUserPermission::getUserId, principal.getSysUser().getId());
        List<Object> permissionIds = sysUserPermissionService.listObjs(queryUserPermission);
        if (!ObjectUtil.isEmpty(permissionIds)) {
            LambdaQueryWrapper<SysPermission> permissionQuery = new LambdaQueryWrapper<SysPermission>().select(SysPermission::getPermission).in(SysPermission::getId, permissionIds);
            List<String> permissions = sysPermissionService.listObjs(permissionQuery, Object::toString);
            principal.setPermissionList(permissions);
        }

        //存入redis中
        String webToken = jwtUtil.generatorToken(MapUtil.builder("username", (Object) principal.getUsername())
                .put("userId", principal.getSysUser().getId())
                .build());
        redisTemplate.opsForValue().set(String.format(RedisConstant.LOGIN_USER, webToken, principal.getSysUser().getId()), principal, 1, TimeUnit.HOURS);

        SysUserVo sysUserVo = BeanUtil.copyProperties(principal.getSysUser(), SysUserVo.class);
        return MapUtil.builder("Authentication", (Object) webToken)
                .put("user", sysUserVo)
                .build();
    }

    @Override
    public void register(RegisterSysUser registerSysUser) {
        if (sysUserService.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, registerSysUser.getUsername())) > 0) {
            throw new ServiceException(Response.SC_BAD_REQUEST, RespConstant.USER_EXISTS);
        }
        //对密码进行加密
        registerSysUser.setPassword(bCryptPasswordEncoder.encode(registerSysUser.getPassword()));
        SysUser sysUser = BeanUtil.copyProperties(registerSysUser, SysUser.class);
        sysUserService.save(sysUser);
    }
}
